昨天的文章講完前端 Nginx 的寫法後,今天就要來進入後端的寫法啦!在昨天的小結提到後端的寫法會用到 Nginx 其他的功能例如:負載平衡、反向代理等等,今天的文章就會一一介紹這些功能的寫法,就讓我們開始今天的文章吧!
首先我們先來看個範例:
upstream backend {
server 0.0.0.0:3000;
}
server {
listen 3000;
listen 443 default ssl;
server_name xxx.com.tw;
ssl_certificate /etc/nginx/ssl/tls.crt;
ssl_certificate_key /etc/nginx/ssl/tls.key;
root /app
client_max_body_size 100m;
charset utf-8;
location /api {
try_files $uri @proxy_to_backend;
}
access_log /var/log/nginx/django-access.log;
error_log /var/log/nginx/django-error.log;
sendfile on;
server_tokens off;
location @proxy_to_backend {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_Header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_read_timeout 300;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
proxy_pass http://backend;
}
location ~ /\.ht {
deny all;
}
}
可以看到後端的 Nginx 設定雖然跟前端的設定很像,但多出了幾個沒有看過的設定,接下來筆者會好好解釋這幾個不一樣的設定,至於其他的設定有興趣的讀者可以看昨天的文章,筆者都有一一說明。
upstream
簡單來說就是設定分流,對於 server 而言所有網頁打的 request 最終都會進到同一台 server 內,所以 server 對於 request 的分流可以說是相當重要,透過 Nginx 我們可以很輕鬆地做到負載平衡(Load Balancer)的功能,而這個寫法就是 upstream
。
upstream
的寫法也很簡單,首先要定義一個 server 讓這個 Nginx 知道要分流時要導到哪個地方,由於筆者都是在 local 端進行設定所以這邊就簡單寫成 0.0.0.0:8080
了,假如讀者本身有多台機器並且有多個 domain,這時候就可以寫多個 server 後面接不同的 domain 了,例如以下這樣:
upstream backend {
server host1.com.tw;
server host2.com.tw;
}
這邊可以看到 server_name
加了一些限制進去了,不再是之前的 _
對全部人開放,畢竟 api 的操作會直接對應到 server 端,所以加一些限制多少都有一些保護的作用在,通常這邊都會設定是跟網址有關,必須要是該網址發的 request 才能被接收。
可以發現這邊的 location
設定又不太一樣了,竟然沒有像前端那樣是根據 path 來決定顯示內容,跑出了一段 location @proxy_to_backend
,這究竟是什麼意思呢?
首先可以看到這段:
location /api {
try_files $uri @proxy_to_backend;
}
可以發現上面這段跟前端的設定檔有點像但是又有些地方不一樣,跑出了 @proxy_to_backend
,在 Nginx 中 @
這個關鍵字代表著一個 named location
,通常會使用 @
這個關鍵字就是因為不是一個正常的 path 或者用 regular expression 定義的 path,所以當我們要使用 Nginx 提供的 reverse-proxy 功能就必須要用到這種方式。
為了不跟前端的路由打架,因此這邊通常都會定義一個後端專屬的 path 並且把所有的 request 都經由 reverse-proxy 進行處理。
接下來就要來定義 reverse-proxy 要做的內容了,前面提到 @
這個關鍵字代表著一個 named location
,所以可想而知前面會用一個 location
的關鍵字來處理這個 reverse-proxy 的內容,寫法就像下面這樣。
location @proxy_to_backend {
# 以下略
}
最後這邊又多了一個 location
的定義:
location ~ /\.ht {
deny all;
}
看到 deny
這個字就很清楚是要拒絕某些東西了,所以上面這個 location 的寫法簡單來說就是當這個 request 我無法解析時,Nginx 就自動幫我全部拒絕吧,筆者覺得這段在後端的設定中是一定要加的,這樣就可以減少很多 server 被誤打的流量。
proxy_set_header
proxy_set_header
就是要設定一些 HTTP headers,基本上要設定的 Headers 方向很簡單,就是要記錄使用者是在從哪個 IP 來的,而這個設定的方法就可以藉由 X-Forwarded-For
以及 X-Real-IP
達成這項功能,而 X-Forwarded-Proto
最主要的功能就是把 header 的內容繼續往下傳遞,最後由於我們有用了 upstream
進行分流設定,假如今天有兩台 server 同時都跑一樣的內容,因為 server 的 IP 都不一樣會導致 request 的 host 看起來也不一樣,這時候為了方便控管就可以利用 HOST $http_host
的方式進行設定。
proxy_redirect
由於 reverse proxy server 會進行 url 的重新導向,為了不讓重新導向的過程中發生錯誤,這時候我們可以設定 proxy_redirect
,將這項功能關閉就不會進行任何的 url redirect。
proxy_read_timeout
proxy_read_timeout
簡單來說就是設定一個 timeout 當我的 response 回傳時間過久的時候就把 connection 關閉不要再繼續等了,這邊的 timeout 時間是以 秒數(s)
為單位,讀者這邊在設定的時候要特別注意喔!
proxy_buffers
我們都知道 server 很常會因為要處理多個 request 導致 response 回傳結果變慢,這時候通常都會利用 cache 的方式來加速回傳時間,而 Nginx 也有類似的作法那就是 buffering,透過 buffering 的大小設定就可以讓同一個 request 的回傳結果先暫存起來,這樣就不用頻繁的跟 server 拿資料了。
proxy_buffer_size
proxy_buffer_size
就是用來設定 buffering 的大小。
proxy_pass
proxy_pass
簡單來說就是要把 request 導到 server 的 URL,但還記得上面寫了一個 upstream
嗎?由於我們在正上方已經先定義好分流的位置了,所以這時候的 proxy_pass
就可以寫上 upstream
的名稱,並且在前方加上 http://
即可,就像下面這樣:
upstream backend {
# 以下略
}
location @proxy_to_backend {
proxy_pass: http://backend;
}
access_log
簡單來說就是用來查看 access 到此 server 的 log,當 Nginx 啟動時會預設開啟這個 access_log
並且將檔案擺放在 /etc/nginx
底下,透過 access_log
的設定可以很輕鬆的將這個 server 的 log 設定到指定的位置以及指定的檔案名稱非常方便。
只要有 access 就一定會有機率會失敗,想當然大家都不希望會失敗這樣就會顯得這個 server 相當不穩定,這時候 Nginx 也有提供 error_log
的設定,就可以讓工程師很輕鬆地知道自己的系統哪些環節有問題了,設定的方式也跟 access_log
一模一樣。
sendfile
主要是用了 Linux 系統中的 sendfile 系統,透過 sendfile 我們可以加速檔案的讀取,讓檔案不會花很多時間在經過任何多餘核心和使用者層級間的資料複製,可以直接從指定的裝置輸出,不過 nginx 預設是 off
所以這邊如果要使用 sendfile 的話要記得設定成 on
。
由於 server 都會有被攻擊的可能性,既然我們都利用 Nginx 當作 reverse-proxy server 了,想當然我們也要關閉一些設定來降低 server 被攻擊的可能性,而 server_tokens
就是個很好的例子,透過將 server_tokens
關閉的方式我們就可以隱藏 server 版本藉此拉高攻擊者要攻擊的成本。
花了這麼多的時間終於把本系列文會用到的觀念全部都說明一遍了,不曉得 Nginx 的觀念會不會太難吸收呢?但目前如果都單純只是介紹觀念的話真的不太有感覺,畢竟還是要親眼看到畫面才比較有真實感,而且也可以確認自己終於會一些 DevOps 的技巧了,所以接下來剩下的幾個篇幅筆者要來實作整個網站的前後端,並且利用前面所學的 Docker、K8s、Nginx 建立出一個網站出來。
如果對於文章有任何問題都歡迎留言給我,那我們就明天的文章見嘍~